home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 436_01 / incon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-07  |  26.8 KB  |  871 lines

  1. /*************************************************************************
  2.     Source file:  INCON.C
  3.  
  4.     This is the main input routine; it accepts keyboard entries from
  5.     the user and builds an output string, which is copied to the i/o
  6.     buffer passed from the caller.  Internal support routines are
  7.     declared below; external routines and data definitions are in
  8.     the following files:
  9.  
  10.         INDEMO    C            Driver routine for testing and debugging.
  11.         INALPHA    C            Alpha input handler.
  12.         INFLOAT    C            Floating-point input handler.
  13.         ININTGR    C            Integer input handler.
  14.         INTEMPL    C            Template input handler.
  15.         INUTIL    C            Public utility routines.
  16.         INCON        H            State data used by INCON.
  17.         INDECL    H            Prototypes and descriptions of utility routines.
  18.         INDEFS    H            Definitions, constants, and macros.
  19.         INSTATS  H            Header for Stat Box routine.
  20.         STRINGZ  ASM        Public string manipulation routines.
  21.         STRINGZ    H            Prototypes and descriptions for STRINGZ.ASM.
  22.         STRINGZ    OBJ        Created from STRINGZ.ASM.
  23.  
  24. Revision History
  25. ----------------
  26.  
  27.         Date                Revision
  28.         -----                -----------------------------------------------------
  29.         93/08                * Release version 2.0.
  30.                             * Extensive revision of v1.0;
  31.                                 separate routines for handling each type of
  32.                                 input field.
  33.                             * Floating-point fields no longer treated as
  34.                                 templates.
  35.                             * Character matching handled by each input handler.
  36.                             * Added mixed template type.
  37.                             * [Backspace] now deletes the last character in
  38.                                 templates and other fields where the cursor
  39.                                 cannot move beyond that character.
  40.                             * Changed the fill character in template, float,
  41.                                 and hidden fields to the Fill value passed in
  42.                                 the message block, so that those fields display
  43.                                 that character in vacant input slots.
  44.         94/05                * Release version 3.0.
  45.                             * Internal optimizations in handler routines.
  46.                             * Corrected bug in Numpad+ and Numpad- handling.
  47.                             * Added Stats() to print status of InCon flags
  48.                                 and parameters after modification, if any,
  49.                                 by initialization routines.
  50.                             * Added Debug flag to control display of Stats
  51.                                 Box and run-time error messages.
  52.         94/08                * Release version 3.1.
  53.                             * Minor fixes to float field handling.
  54.  
  55.     Compiler:  Borland Turbo C 2.01
  56.  
  57.     INCON source files and the object and library files created from
  58.     them are:
  59.         Copyright (c) 1993-94, Richard Zigler.
  60.     You may freely distribute unmodified source, object, and library
  61.     files, and incorporate them into your own non-commercial software,
  62.     provided that this paragraph and the program name and copyright
  63.     strings defined in INCON.C are included in all copies.
  64. *************************************************************************/
  65.  
  66. #include <bios.h>
  67. #include <conio.h>
  68. #include <ctype.h>
  69. #include <dos.h>
  70. #include <stdlib.h>
  71. #include <string.h>
  72. #include "indefs.h"
  73. #include "incon.h"
  74. #include "indecl.h"
  75. #include "stringz.h"
  76.  
  77. const char            ProgName[]    = "INCON 3.1 ";
  78. const char            Copyright[]    = "Copyright (c) 1993-94, Richard Zigler";
  79.  
  80. short                    Chr                ;        /* keyboard character                */
  81. short                    Col                ;        /* input field column                */
  82. BFLAG                    EscSet            ;        /* [Esc] key pressed?                */
  83. short                    FieldMin            ;        /* scrolling field first char        */
  84. WORD                    Fill                ;        /* field fill character                */
  85. BIT_FLAGS            Flags                ;        /* message block flags word        */
  86. BFLAG                    InBegin            ;        /* first input character?            */
  87. BFLAG                    More                ;        /* get more input?                    */
  88. BFLAG                    Move                ;        /* move the cursor?                    */
  89. short                    Prec                ;        /* field min width/decimal chars    */
  90. short                    Row                ;        /* input field row                    */
  91. short                    StrLength        ;        /* output string length                */
  92. BFLAG                    Update            ;        /* update display?                    */
  93. short                    Width                ;        /* field max width                    */
  94. char                *    DisplayStr        ;        /* display string if Scroll;        */
  95.                                                     /*  template array if Template    */
  96. char                *    InStr                ;        /* pointer to i/o buffer            */
  97.                                                     /*  passed from calling routine    */
  98. char                *    OutStr            ;        /* build output string here;        */
  99.                                                     /*  OutStr copied to InStr if        */
  100.                                                     /*  input ok                            */
  101.  
  102. /**** Module-wide Data ****/
  103.  
  104. static WORD            BufOff            ;        /* i/o buffer offset                    */
  105. static WORD            BufSeg            ;        /* i/o buffer segment                */
  106. static WORD            FieldAttr        ;        /* input field video attributes    */
  107. static short        FieldMax            ;        /* scrolling field last char        */
  108. static WORD            KeyOff            ;        /* extended-key list offset        */
  109. static WORD            KeySeg            ;        /* extended-key list segment        */
  110. static WORD            NormAttr            ;        /* screen normal attribute            */
  111. static WORD            Pad                ;        /* output string pad character    */
  112. static short        Visible            ;        /* scrolling field display width    */
  113. static char        *    xKeyList            ;        /* extended-key list passed        */
  114.                                                     /*  from calling routine            */
  115.  
  116. /**** Debug Status Declarations ****/
  117.  
  118. #define INCON_STATS 1                        /* 1 = enable/0 = disable stats    */
  119. #if INCON_STATS
  120. #include "instats.h"
  121. #endif
  122.  
  123. /**** Local Routines ****/
  124.  
  125. static short    pascal    Error                ( void                                    );
  126. static void        pascal    FreeBuffers        ( void                                    );
  127. static int        pascal    Init                ( MBLOCK far *                            );
  128. static void        pascal    Scroll            ( int                                        );
  129.  
  130. /*************************************************************************
  131.     InCon()
  132. *************************************************************************/
  133.  
  134. short pascal InCon
  135. (
  136. MBLOCK far        *    BlockPtr                    /* pointer to message block        */
  137. )
  138. {
  139. register int        pos = 0                ;    /* tracks cursor                        */
  140. register int        work                    ;    /* integer working storage            */
  141. HANDLER                p_handler = NULL    ;    /* ptr to input handling routine    */
  142. STATES                state         = stInit;    /* input state                            */
  143.  
  144. /* extended character codes for edit keys used by InCon()                    */
  145.  
  146. static char EditKeys[] =
  147.     {
  148.     HOME                ,                            /* move to start of input field    */
  149.     END                ,                            /* move to end of input field        */
  150.     LEFT                ,                            /* move left one character            */
  151.     RIGHT                ,                            /* move right one character        */
  152.     C_LEFT            ,                            /* move left one word                */
  153.     C_RIGHT            ,                            /* move right one word                */
  154.     DEL                ,                            /* delete character at cursor        */
  155.     C_L                ,                            /* delete word left                    */
  156.     C_R                ,                            /* delete word right                    */
  157.     C_END                ,                            /* delete to end of field            */
  158.     C_HOME            ,                            /* delete to start of field        */
  159.     K_PLUS            ,                            /* special exit or +                    */
  160.     K_MINUS            ,                            /* special exit or -                    */
  161.     0
  162.     };
  163.  
  164. if ( !Init( BlockPtr ) )                    /* init globals & environment        */
  165.     {
  166.     *p_handler =    Flags.Template         ?    hTemplateField    :
  167.                         Flags.Type == FLOAT    ?    hFloatField        :
  168.                         Flags.Type == INTGR    ?    hIntegerField    :
  169.                                                         hAlphaField        ;
  170.  
  171.     pos = p_handler( state, pos );        /* do type-specific init            */
  172.    }
  173. if ( (Chr = Error()) != 0 )                /* check for run-time errors        */
  174.     {
  175.     textattr( NormAttr );                    /* reset screen colors                */
  176.     return( Chr | 0x8000 );                    /* turn on the high bit of Chr    */
  177.     }
  178.  
  179. #if INCON_STATS
  180. if ( Flags.Debug )
  181.     Stats( state, StatFlags );                /* init stats window                    */
  182. #endif
  183.  
  184. /****
  185.     Display delimiters if Delimit flag is set.  The input field
  186.     start column is incremented after placing the left delimiter.
  187. ****/
  188.  
  189. if ( Flags.Delimit )
  190.     {
  191.     PutCursor( Row, Col++ );
  192.     putch( L_DELIM );
  193.     PutCursor( Row, Col + Visible );
  194.     putch( FieldMax < StrLength ? R_CONT : R_DELIM );
  195.     PutCursor( Row, Col );
  196.     }
  197.  
  198. /****
  199.     Set up the input field.  If the Template flag is set, fill the
  200.     input field with spaces; otherwise, fill it with Fill.  For
  201.     non-scrolling fields, Visible is set equal to Width in Init().
  202. ****/
  203.  
  204. WriteMany((Flags.Template ? (char) ' ' : (char) Fill), FieldAttr, Visible);
  205.  
  206. /****
  207.     Display default input string if one was passed in from caller.
  208.     If the Scroll flag is set, display Visible characters from the
  209.     left of OutStr; otherwise display the entire string.
  210. ****/
  211.  
  212. if ( StrLength )
  213.     cputs( Flags.Scroll ?
  214.                 (char *) LeftStr( DisplayStr, OutStr, Visible ) :
  215.                     OutStr );
  216.  
  217. InBegin    = More = YES;                        /* initialize flags                    */
  218. EscSet    = NO;
  219.  
  220. while ( KEYREADY )                            /* clear keyboard buffer            */
  221.     KEYREAD;
  222.  
  223. /****
  224.     Get input until the field is filled, or until no more is required.
  225.     This is the main loop, which is divided into four sections:  the
  226.     first handles edit and other extended keys; the second handles all
  227.     other keys; the third calls the input handler routine and checks
  228.     for automatic exit in unconfirmed fields; the fourth handles cursor
  229.     moves and display string updates flagged by the input handler.
  230. ****/
  231.  
  232. while ( More )                                    /**** start main loop            ****/
  233.     {
  234.  
  235.     /****
  236.         Place cursor after field initialization and during subsequent
  237.         activity in the field.
  238.     ****/
  239.  
  240.     work = Col + pos - FieldMin;
  241.     PutCursor( Row, work > MAXCOL ? MAXCOL : work );
  242.  
  243.     /****
  244.         Update and Move monitor whether the user has edited the input
  245.         string or merely moved the cursor.  If the cursor moves left,
  246.         Move is decremented; otherwise, it is incremented.  If the
  247.         input string has been modified, Update is incremented.
  248.     ****/
  249.  
  250.     Move    = Update = 0;
  251.     state    = stError;
  252.     Chr    = KEYREAD;
  253.  
  254.     if ( !LOBYTE(Chr) )
  255.         {                                            /**** extended keys                ****/
  256.         (WORD) Chr >>= 8;
  257.  
  258.         /* extended edit keys are disabled in hidden fields                    */
  259.  
  260.         if ( !Flags.Hide && strchr( EditKeys, Chr ) )
  261.             {
  262.             switch ( Chr )
  263.                 {
  264.                 case HOME        :    state = stMoveToStart        ; break ;
  265.                 case END            :    state = stMoveToEnd            ; break ;
  266.                 case LEFT        :    state = stMoveCharLeft        ; break ;
  267.                 case RIGHT        :    state = stMoveCharRight        ; break ;
  268.                 case C_LEFT        :    state = stMoveWordLeft        ; break ;
  269.                 case C_RIGHT    :    state = stMoveWordRight        ; break ;
  270.                 case C_HOME        :    state = stDeleteToStart        ; break ;
  271.                 case C_END        :    state = stDeleteToEnd        ; break ;
  272.                 case DEL            :    state = stDeleteAtCursor    ; break ;
  273.                 }
  274.             }
  275.         else
  276.             {
  277.  
  278. #if INCON_STATS                                /* display Stat Box if enabled    */
  279.             if ( Chr == NUM5 && Flags.Debug )
  280.                 {
  281.                 Stats( state, StatFlags );
  282.                 continue;
  283.                 }
  284. #endif
  285.  
  286. __Extended:                                        /* check caller's extended list    */
  287. ;
  288.             if ( Flags.xKeys && strchr( xKeyList, Chr ) )
  289.                 More = NO;
  290.             else
  291.                 ERROR_BEEP;
  292.             continue;                            /* with while(More)                    */
  293.             }
  294.         }                                            /**** extended keys                ****/
  295.     else
  296.         {                                            /**** ASCII keys                    ****/
  297.         work = (WORD) Chr >> 8;
  298.         if ( work == K_PLUS )                /* [Numpad +] and [Numpad -]        */
  299.             {                                        /*  are treated as special exit    */
  300.             Chr = work;                            /*  keys in numeric fields            */
  301.             state = stExitPlus;
  302.             }
  303.         else if ( work == K_MINUS )
  304.             {
  305.             Chr = work;
  306.             state = stExitMinus;
  307.             }
  308.         else
  309.             {
  310.             switch ( Chr &= 0xFF )
  311.                 {
  312.                 case TAB            :    goto  __Extended                ;
  313.                 case BS            :    state = stDeleteCharLeft    ; break ;
  314.                 case CR            :    state = stQuit                    ; break ;
  315.                 case C_L            :    state = stDeleteWordLeft    ; break ;
  316.                 case C_R            :    state = stDeleteWordRight    ; break ;
  317.                 case ESC            :    state = stFieldClear            ; break ;
  318.                 default            :    state = stCharMatch            ; break ;
  319.                 }
  320.             }
  321.         }                                            /**** ASCII keys                    ****/
  322.     pos = p_handler( state, pos );
  323.     EscSet = (state == stFieldClear);    /* set EscSet to YES or NO            */
  324.  
  325.     /****
  326.         Most cursor moves are handled by the cursor update at the
  327.         top of the while() loop.  Scrolling fields, though, impose
  328.         additional conditions.
  329.     ****/
  330.  
  331.     if ( Move )
  332.         {
  333.         if ( Flags.Scroll && (pos <= FieldMin || pos >= FieldMax) )
  334.             Scroll( pos );
  335.         }
  336.  
  337.     /****
  338.         The last entry caused a change in the output string.  If the
  339.         Scroll flag is set, call Scroll() to update the displayed
  340.         substring regardless of whether or not the cursor has moved
  341.         out of the visible field.  Otherwise, if this is not a hidden
  342.         field (or if a hidden field has been cleared with [Esc]),
  343.         display the new input string and fix the field mask.
  344.     ****/
  345.  
  346.     else if ( Update )
  347.         {
  348.         if ( Flags.Scroll )
  349.             Scroll( pos );
  350.         else if ( !Flags.Hide || state == stFieldClear )
  351.             {
  352.             PutCursor( Row, Col );
  353.             cputs( OutStr );
  354.             }
  355.       }                                            /* else if (Update)                    */
  356.     if ( More )
  357.         {
  358.         if ( !Flags.Confirm && Update )    /* check for automatic exit        */
  359.             {                                        /*  except on cursor keys            */
  360.             More = Chr =    Flags.Template                ?
  361.                                 strchr( OutStr, Fill )    ?    -1    : 0 :
  362.                                 StrLength < Width            ?    -1 : 0 ;
  363.             if ( !More )
  364.                 {
  365.                 if ( Flags.Template && Flags.Strip )
  366.                     p_handler( stQuit, pos );                /* strip template        */
  367.                 goto __Beep;                                    /* signal auto exit    */
  368.                 }
  369.             }
  370.         if ( !(Move || Update) )            /* if last key caused neither        */
  371.             {                                        /*  exit, move, nor update,        */
  372. __Beep:
  373. ;
  374.             ERROR_BEEP;                            /*  key is illegal                    */
  375.             continue;                            /* with while (More)                    */
  376.             }
  377.         else
  378.             InBegin = NO;
  379.         }
  380.  
  381.     /****
  382.         If the input string only partly fills the field, mask the
  383.         remainder of the field with Fill characters if input is to
  384.         continue; otherwise, clear any left-over mask from the field.
  385.     ****/
  386.  
  387.     work = StrLength - FieldMin;
  388.     if ( work < Visible )
  389.         {
  390.         PutCursor( Row, Col + work );
  391.         WriteMany( More ? (char)Fill : ' ', FieldAttr, Visible - work );
  392.         }
  393.     }                                                /**** while (More)                ****/
  394.  
  395. if ( Chr == 0 || Chr == K_PLUS || Chr == K_MINUS )        /* if input ok        */
  396.     {
  397.     switch( Flags.Justify )
  398.         {
  399.         case NJUST :                                                /* no justify        */
  400.             strcpy( InStr, OutStr );
  401.             break;
  402.         case LJUST :                                                /* left justify    */
  403.             lJust( InStr, OutStr, Width, (char) Pad );
  404.             break;
  405.         case CJUST :                                                /* center string    */
  406.             cJust( InStr, OutStr, Width, (char)Pad );
  407.             break;
  408.         case RJUST :                                                /* right justify    */
  409.             rJust( InStr, OutStr, Width, (char)Pad );
  410.             break;
  411.         }
  412.     }
  413. textattr( NormAttr );                                            /* reset colors    */
  414. PutCursor( Row, (Flags.Delimit ? --Col : Col) );        /*  and cursor        */
  415.  
  416. FreeBuffers();
  417. while ( KEYREADY )                            /* clear keyboard buffer            */
  418.     KEYREAD;
  419. return( Chr );                                    /* error extended code                */
  420. }                                                    /**** InCon()                        ****/
  421.  
  422. /*************************************************************************
  423.     Error()
  424.     Check parameters passed in message block for errors.
  425. *************************************************************************/
  426.  
  427. #define ERRP        ".  Press any key..."
  428.  
  429. enum ErrCodes
  430.     {
  431.     FieldPrec        = 1,
  432.     FieldWidth            ,
  433.     DefString            ,
  434.     FloatPrec            ,
  435.     FloatDecimal        ,
  436.     FillTemplate        ,
  437.     BadTemplate            ,
  438.     NoMemory                ,
  439.     NullBuffer            ,
  440.     }                        ;
  441.  
  442. static short pascal Error( void )
  443. {
  444. register int        err_code  = 0;            /* run-time error code                */
  445. static char        *    err_str[] =
  446.     {
  447.     "\a INCON error"                                            ,
  448.     "Invalid field precision"                                ,
  449.     "Invalid field width or scroll visible length"    ,
  450.     "Default input string too long"                        ,
  451.     "Type float; precision is invalid"                    ,
  452.     "Type float; no room for decimal point"            ,
  453.     "Fill character appears in template"                ,
  454.     "Invalid template"                                        ,
  455.     "Insufficient memory for internal buffers"        ,
  456.     "Input/output buffer pointer is NULL"                ,
  457.     };
  458.  
  459. if ( Prec > Width )
  460.     err_code = FieldPrec;
  461.  
  462. /****
  463.     Visible is used here to determine whether a Width error has occurred
  464.     because Visible will be equal to Width for non-scrolling fields, and
  465.     Visible characters must fit on the screen line for scrolling fields.
  466. ****/
  467.  
  468. else if (Visible <= 0 || (Col + Visible + (Flags.Delimit ? 2 : 0)) > MAXCOL)
  469.     err_code = FieldWidth;
  470. else if ( StrLength > Width )
  471.     err_code = DefString;
  472. else if ( Flags.Type == FLOAT && Prec <= 0 )
  473.     err_code = FloatPrec;
  474. else if ( Flags.Type == FLOAT && (Width - Prec - 1) < 0 )
  475.     err_code = FloatDecimal;
  476. else if ( Flags.Template && strchr( InStr, LOBYTE(Fill) ) )
  477.     err_code = FillTemplate;
  478. else if ( Flags.Template && *OutStr == '\0' )
  479.     err_code = BadTemplate;
  480. else if
  481.     (
  482.     OutStr == NULL
  483.     ||
  484.     (DisplayStr == NULL && (Flags.Scroll || Flags.Template))
  485. #if INCON_STATS
  486.     ||
  487.     (Flags.Debug && (SaveScreen == NULL || SaveStats == NULL))
  488. #endif
  489.     )
  490.     err_code = NoMemory;
  491. else if ( InStr == NULL )
  492.     err_code = NullBuffer;
  493.  
  494. /* Release buffers and print run-time error message.                            */
  495.  
  496. if ( err_code )
  497.     {
  498.     FreeBuffers();
  499.     if ( Flags.Message )                        /* if messaging enabled                */
  500.         {
  501.         PutCursor( Row, 0 );
  502.         WriteMany( ' ', FieldAttr, MAXCOL );
  503.         cprintf
  504.             (
  505.             "%s %d: %s%s",
  506.             *err_str, err_code, *(err_str + err_code), ERRP
  507.             );
  508.         KEYREAD;                                    /* wait for keypress                    */
  509.         cputs( "\r\n" );
  510.         }
  511.     }
  512. return( err_code );
  513. }                                                    /**** Error()                        ****/
  514.  
  515. /*************************************************************************
  516.     FreeBuffers()
  517.     Free allocated memory.
  518. *************************************************************************/
  519.  
  520. static void pascal FreeBuffers( void )
  521. {
  522.  
  523. #if INCON_STATS
  524. if ( SaveStats != NULL )
  525.     free( SaveStats );
  526. if ( SaveScreen != NULL )
  527.     free( SaveScreen );
  528. #endif
  529.  
  530. if ( DisplayStr != NULL )
  531.     free( DisplayStr );
  532. if ( OutStr != NULL )
  533.     free( OutStr );
  534. }
  535.  
  536. /*************************************************************************
  537.     Init()
  538.     This routine transfers the message block contents to internal
  539.     variables and sets up the overall environment for InCon().  Some
  540.     error trapping is done here, as well.  All memory allocation is
  541.     localized to this routine.
  542. *************************************************************************/
  543.  
  544. static int pascal Init
  545. (
  546. MBLOCK far         *    BlockPtr                    /* message block pointer            */
  547. )
  548. {
  549. static    WORD        init = 0;                /* flag first time through            */
  550.  
  551. GetCursor( &Row, &Col );
  552.  
  553. BufOff        = BlockPtr->sblock.BufOff;
  554. BufSeg        = BlockPtr->sblock.BufSeg;
  555. KeyOff        = BlockPtr->sblock.KeyOff;
  556. KeySeg        = BlockPtr->sblock.KeySeg;
  557. Flags            = BlockPtr->sblock.Flags.bflags;
  558. Width            = BlockPtr->sblock.Width;
  559. Prec            = BlockPtr->sblock.Prec;
  560. Visible        = BlockPtr->sblock.Visible;
  561. FieldAttr    = BlockPtr->sblock.Attr;
  562. Fill            = BlockPtr->sblock.Fill;
  563. Pad            = BlockPtr->sblock.Pad;
  564.  
  565. InStr        = (char *) MK_FP( BufSeg, BufOff );            /* default input        */
  566. xKeyList    = (char *) MK_FP( KeySeg, KeyOff );            /* extended-key list    */
  567.  
  568. OutStr = DisplayStr = NULL;                /* initialize buffer pointers        */
  569.  
  570. #if INCON_STATS
  571. SaveScreen = SaveStats = NULL;
  572. #endif
  573.  
  574. if ( !init )
  575.     {
  576.     ++init;
  577.     NormAttr = GetVideoAttr();
  578.     delay( 0 );
  579.     }
  580. if ( !FieldAttr )
  581.     FieldAttr =    ((NormAttr & 0x07) << 4)    |            /* reverse current    */
  582.                     ((NormAttr & 0x70) >> 4)    |            /*  attribute            */
  583.                     ( NormAttr & 0x08)            ;            /* preserve intense    */
  584.  
  585. /* if back/fore still the same, toggle intensity                                */
  586.  
  587. if ( ((FieldAttr & 0x70) >> 4) == (FieldAttr & 0x0F) )
  588.     FieldAttr ^= 0x08;
  589.  
  590. textattr( FieldAttr );
  591.  
  592. if ( Fill < ' ' )                                /* Fill and Pad default to            */
  593.     Fill = ' ';                                    /*  ASCII space                        */
  594. if ( Pad < ' ' )
  595.     Pad = ' ';
  596.  
  597. if ( Flags.Debug )                            /* if Debug flag is set,            */
  598.     Flags.Message = YES;                        /*  enable error messages            */
  599.  
  600. if ( xKeyList == NULL || !*xKeyList )    /* xKeyList invalid                    */
  601.     Flags.xKeys = NO;
  602.  
  603. if ( Flags.Type == FLOAT )                    /* float fields are not                */
  604.     Flags.Template = NO;                        /*  templates                            */
  605.  
  606. if ( !Flags.Template && (Flags.Type & INTGR) )
  607.     {
  608.     Flags.Hide        =                            /* turn off Hide and Scroll in    */
  609.     Flags.Scroll    = NO;                        /*  non-template numeric fields    */
  610.     lTrim( InStr, InStr );                    /* strip leading and trailing        */
  611.     rTrim( InStr, InStr );                    /*  spaces and control codes        */
  612.     }
  613.  
  614. StrLength = strlen( InStr );
  615. if ( Width <= 0 )                                /* attempt to remedy if invalid    */
  616.     Width = StrLength;                        /* if fails, Error() aborts        */
  617.  
  618. /* if i/o buffer null or allocation fails, return immediately to InCon    */
  619.  
  620. if ( (char *) InStr )
  621.     {
  622.     if ( Width && (OutStr = calloc( Width + 1, sizeof(char) )) != NULL )
  623.         {
  624.         if ( StrLength )
  625.             LeftStr( OutStr, InStr, Width );        /* don't allow overflow        */
  626.  
  627.         if ( Flags.Hide )                        /* disable scrolling for            */
  628.             Flags.Scroll = NO;                /*  hidden input fields                */
  629.  
  630.         if (
  631.             !Flags.Template
  632.             &&
  633.             Flags.Type == INTGR
  634.             &&
  635.             strchr( OutStr, '.' )
  636.             )
  637.             {
  638.             Flags.Type = FLOAT;                /* force signed float input if    */
  639.             Flags.Sign = YES;                    /*  '.' in non-template integer    */
  640.             }
  641.  
  642.         if ( Flags.Template )                /* input template                        */
  643.             {
  644.             Flags.Justify    = NJUST;            /* no justification/scrolling        */
  645.             Flags.Scroll    = NO;
  646.             if ( Width > StrLength )        /* hold width/prec to length        */
  647.                 Width = StrLength;            /*  of template                        */
  648.             Prec = Width;
  649.             if ( Flags.Type >= INTGR )        /* use [Numpad +/-] to indicate    */
  650.                 Flags.Sign = NO;                        /* signed input                */
  651.             DisplayStr = malloc( Width + 1 );    /* type flags                    */
  652.             }
  653.         else if
  654.             (
  655.             ((Col + Width) > MAXCOL)        /* field longer than screen line    */
  656.             &&
  657.             (Flags.Type < INTGR)                /* field is alpha/upper                */
  658.             &&
  659.             !Flags.Scroll                        /* non-scrolling                        */
  660.             &&
  661.             !Flags.Hide                            /* Error() aborts if hidden        */
  662.             )                                        /*  or non-alpha field                */
  663.             {
  664.             Flags.Scroll    = YES;                /* force scrolling                */
  665.             Flags.Delimit    = NO;                    /* turn off delimiters            */
  666.             Visible            = MAXCOL - Col;    /* visible out to end of line    */
  667.             }
  668.  
  669.         /****
  670.             Initialize scroll variables.  FieldMin and FieldMax
  671.             index the visible range of characters in OutStr as
  672.             the user edits the string or moves through it with
  673.             the cursor keys.  Initially, FieldMin is zero for
  674.             all types of fields and FieldMax is set to Visible
  675.             for scrolling fields, so that Visible characters
  676.             are displayed from the left end of the default string.
  677.             For non-scrolling fields, FieldMax and Visible both are
  678.             set to Width, which allows for simplification of some
  679.             statements in the handler routines; the same indexing
  680.             can be applied to scrolling and non-scrolling fields.
  681.         ****/
  682.  
  683.         if ( Flags.Scroll )
  684.             DisplayStr = malloc( Visible + 1 );
  685.         else
  686.             Visible = Width;
  687.  
  688.         FieldMin = 0;
  689.         FieldMax = Visible;
  690.  
  691.         /****
  692.             If Debug flag is set, allocate buffers for saving screen
  693.             contents of window and of data under window.
  694.         ****/
  695.  
  696. #if INCON_STATS
  697.         if ( Flags.Debug )
  698.             {
  699.             SaveScreen = malloc( SaveSize );
  700.             SaveStats  = malloc( SaveSize );
  701.             }
  702. #endif
  703.         }                                            /* if (OutStr)                            */
  704.    }                                                /* if (InStr )                            */
  705.  
  706. return ( InStr == (char *) 0 || OutStr == (char *) 0 );
  707. }                                                    /**** Init()                        ****/
  708.  
  709. /*************************************************************************
  710.     Scroll()
  711.     This routine handles scrolling input fields.  FieldMin and FieldMax
  712.     index the beginning and end of the visible part of OutStr.  They form
  713.     a sliding "window", which is Visible characters wide, into the entire
  714.     input string.  This routine is called to update the display whenever
  715.     OutStr has been changed by the user, and whenever the cursor has been
  716.     moved outside the bounds of the visible field.
  717. *************************************************************************/
  718.  
  719. static void pascal Scroll
  720. (
  721. register int        Pos                        /* position in input string        */
  722. )
  723. {
  724.  
  725. /****
  726.     If the cursor is at or below the left boundary of the field,
  727.     set the new left boundary one character to the left of the
  728.     cursor or to the beginning of the input string, whichever
  729.     is greater.  That keeps the character to the left of the
  730.     cursor visible, so that "delete left" is not done blind.
  731. ****/
  732.  
  733. if ( Pos <= FieldMin )
  734.     {
  735.     FieldMin = Pos > 0 ? Pos - 1 : Pos ;
  736.     FieldMax = FieldMin + Visible;
  737.     }
  738.  
  739. /****
  740.     If the cursor is at or above the right boundary of the field,
  741.     set the new right boundary at the cursor position.  FieldMax
  742.     is a 1-based index rather than a 0-based pointer, so it is
  743.     set to one more than the cursor position.
  744. ****/
  745.  
  746. else if ( Pos >= FieldMax )
  747.     {
  748.     FieldMax = Pos >= Width ? Pos : Pos + 1 ;
  749.     FieldMin = FieldMax - Visible;
  750.     }
  751.  
  752. if ( Flags.Delimit )                            /* display delimiters                */
  753.     {
  754.     PutCursor( Row, Col - 1 );
  755.     putch( FieldMin > 0 ? L_CONT : L_DELIM );
  756.     PutCursor( Row, Col + Visible );
  757.     putch( FieldMax < StrLength ? R_CONT : R_DELIM );
  758.     }
  759.  
  760. /****
  761.     Display Visible characters of the output string, beginning at
  762.     FieldMin.  The string functions expect a 1-based index into
  763.     the source string, so FieldMin is incremented before it is
  764.     passed to MidStr().  All of the string functions return a
  765.     pointer to the null-terminated target string (first parameter),
  766.     which is a substring of the source string (second parameter).
  767. ****/
  768.  
  769. PutCursor( Row, Col );
  770. cputs( (char *) MidStr( DisplayStr, OutStr, FieldMin + 1, Visible ) );
  771.  
  772. }                                                    /**** Scroll()                        ****/
  773.  
  774. #if INCON_STATS
  775.  
  776. /*************************************************************************
  777.     Stats()
  778.     Displays parameters after field initialization.  This routine is
  779.     compiled only if the constant INCON_STATS is non-zero.
  780. *************************************************************************/
  781.  
  782. static void pascal Stats( STATES State, WORD * Flags )
  783. {
  784. register int        bit,
  785.                         ndx;
  786. int                    x1,
  787.                         x2,
  788.                         y1,
  789.                         y2;
  790.  
  791. gettextinfo( &TextInfo );                    /* save caller's window stats        */
  792. x1 = TextInfo.winleft;
  793. x2 = TextInfo.winright;
  794. y1 = TextInfo.wintop;
  795. y2 = TextInfo.winbottom;
  796.  
  797. /**** Display Window Layout
  798.  
  799. Field___________________
  800. Input___________________
  801. ________________________
  802. ________________________
  803. ________________________
  804.  ╔════════════════════════════════════════════════════════════════════════════╗
  805.  ║ INCON 3.1                            Copyright (c) 1993-94, Richard Zigler ║
  806.  ║ ioBuf segment:offset = XXXX:XXXX       xKeyList segment:offset = XXXX:XXXX ║
  807.  ║ Width:  XX   Prec:  XX   Visible:  XX     Attr:  XX   Fill:  XX   Pad:  XX ║
  808.  ║ Flags:  B BBB BB B B B B B B B B B B     Use [Numpad 5] to toggle Stat Box ║
  809.  ╚════════════════════════════════════════════════════════════════════════════╝
  810.  
  811. ****/
  812.  
  813. if ( State == stInit )                                    /* if initializing        */
  814.     {
  815.     Cursor( SAVE );
  816.     Cursor( OFF );
  817.     gettext( STAT_WINDOW, SaveScreen );                /* save screen contents    */
  818.  
  819.     for ( bit = 0x8000, ndx = 0 ; StatsMask[ndx] ; ndx++ )
  820.         {
  821.         if ( StatsMask[ndx] == 'B' )
  822.             {
  823.             StatsBuf[ndx] = *Flags & bit ? '1' : '0' ;
  824.             (WORD) bit >>= 1;
  825.             }
  826.         else
  827.             StatsBuf[ndx] = '\x20';
  828.         }
  829.     StatsBuf[ndx] = '\0';
  830.  
  831.     window( STAT_WINDOW );                                /* set stat window        */
  832.     clrscr();
  833.     cprintf                                                    /* print modified parms    */
  834.         (
  835.         " ╔══════════════════════════════════════"
  836.         "══════════════════════════════════════╗ "
  837.         " ║ %-37s%s ║ "
  838.         " ║ ioBuf segment:offset = %.4X:%.4X"
  839.         "       xKeyList segment:offset = %.4X:%.4X ║ "
  840.         " ║ Width:  %.2X   Prec:  %.2X   Visible:  %.2X"
  841.         "     Attr:  %.2X   Fill:  %.2X   Pad:  %.2X ║ "
  842.         " ║ Flags:  %-33sUse [Numpad 5] to toggle Stat Box ║ "
  843.         " ╚══════════════════════════════════════"
  844.         "══════════════════════════════════════╝"
  845.         , ProgName,    Copyright
  846.         , BufSeg,    BufOff
  847.         , KeySeg,    KeyOff
  848.         , Width,        Prec
  849.         , Visible,    FieldAttr
  850.         , Fill,        Pad
  851.         , StatsBuf
  852.         );
  853.  
  854.     gettext( STAT_WINDOW, SaveStats );                /* save stat block        */
  855.     window( x1, y1, x2, y2 );                            /* restore window            */
  856.     Cursor( RESTORE );                                    /*  and cursor                */
  857.     Cursor( ON );
  858.     }
  859. else
  860.     {
  861.     puttext( STAT_WINDOW, SaveStats );                /* display stat block    */
  862.     while ( KEYREAD != (NUM5 << 8) )                    /* wait for [Numpad 5]    */
  863.         ERROR_BEEP;
  864.     }
  865. puttext( STAT_WINDOW, SaveScreen );        /* restore screen                        */
  866. }                                                    /**** Stats()                        ****/
  867.  
  868. #endif
  869.  
  870. /**** EOF:  INCON.C ****/
  871.